#include <halintrpt.h>
#include <halglobal.h>

/*********************************************************************************
 * 
 * hal_intrpt_init - 初始化中断源结构体
 * 
 * DESCRIPTION
 * 初始化中断源结构体
 */

void hal_intrpt_init (void)
    {
    intsrcdsc_init (&osmachine);

    return;
     }

/*********************************************************************************
 * 
 * intsrcdsc_init - 初始化三类中断源的结构体
 * 
 * DESCRIPTION
 * 初始化三类中断源的结构体：
 * - 主中断
 * - 次级中断
 * - 外部中断
 */

void intsrcdsc_init 
    (
    mach_t * mach
    )
    {
    intsrcdsc_t * intsrcdsc = mach->intsrcdsc;
    uint_t        nbr       = mach->intsrcdscnbr;
    uint_t        i;

    /* 主中断初始化 */

    for (i = MAJINT_SRC_START; i < MAJINT_SRC_END; i++)
        {
        intsrcdsc_t_init (&intsrcdsc[i], MAJINT_FLAG, 0, i - MAJINT_OFFSET, i);
        }

    /* 次级中断初始化 */

    for (i = SUBINT_SRC_START; i < SUBINT_SRC_END; i++)
        {
        intsrcdsc_t_init (&intsrcdsc[i], SUBINT_FLAG, 0, i - SUBINT_OFFSET, i);
        }

    /* 外部中断初始化 */

    for (i = EXTINT_SRC_START; i < EXTINT_SRC_END; i++)
        {
        intsrcdsc_t_init (&intsrcdsc[i], EXTINT_FLAG, 0, i - EXTINT_OFFSET, i);
        }

    return;
    }

/*********************************************************************************
 * 
 * intsrcdsc_t_init - 初始化一个中断源管理结构体
 * 
 * DESCRIPTION
 * 初始化一个中断给管理结构体：
 * - 该中断类型
 * - 该中断状态
 * - 该中断在其同类中断中的序号
 * - 该中断在所有中断中的序号
 */

void intsrcdsc_t_init 
    (
    intsrcdsc_t * intsrcdsc,
    u32_t         flag,
    u32_t         status,
    u32_t         pndbitidx,
    uint_t        irqnbr
    )
    {
    spinlock_init (&intsrcdsc->lock);
    list_init (&intsrcdsc->isrlist);

    intsrcdsc->isrnbr    = 0;
    intsrcdsc->flag      = flag;
    intsrcdsc->status    = status;
    intsrcdsc->pndbitidx = pndbitidx;
    intsrcdsc->irqnbr    = irqnbr;
    intsrcdsc->deep      = 0;
    intsrcdsc->gnrtcnt   = 0;

    return;
    }

/*********************************************************************************
 * 
 * intisrdsc_t_init - 初始化一个中断回调函数管理结构体
 * 
 */

void intisrdsc_t_init 
    (
    intisrdsc_t * intisrdsc,
    u32_t         flag,
    intsrcdsc_t * intsrcdsc,
    void *        device,
    inthandle_t   handle
    )
    {
    list_init (&intisrdsc->list);
    list_init (&intisrdsc->devlist);

    intisrdsc->flag      = flag;
    intisrdsc->intsrcdsc = intsrcdsc;   /* 该 intisrdsc_t 属于 哪个 intsrcdsc_t */
    intisrdsc->refcnt    = 0;
    intisrdsc->device    = device;      /* 记录属于哪个设备描述符地址 */
    intisrdsc->handle    = handle;      /* 记录回调函数地址 */

    return;
    }

/*
 * 处理中断所用到的辅助功能函数：
 * - 获取中断源描述符
 * - 确定中断源
 * - 清除中断源挂起寄存器
 * - 打开中断源
 * - 关闭中断源
 */

/*********************************************************************************
 * 
 * intrpt_return_intsrcdsc - 获取中断源描述符
 * 
 * DESCRIPTION
 */

intsrcdsc_t * intrpt_return_intsrcdsc
    (
    uint_t ifdidx
    )
    {
    intsrcdsc_t * intsrcdsc;

    /* 中断序号值非法 */

    if (ifdidx >= osmachine.intsrcdscnbr)
        {
        return NULL;
        }

    /* 返回对应的 intsrcdsc_t 结构体 */

    intsrcdsc = &(osmachine.intsrcdsc[ifdidx]);

    return intsrcdsc;
    }

/*********************************************************************************
 * 
 * intrpt_add_intisr_to_intsrcdsc - 
 * 
 * DESCRIPTION
 */

bool_t intrpt_add_intisr_to_intsrcdsc 
    (
    intsrcdsc_t * intsrcdsc, 
    intisrdsc_t * intisrdsc
    )
    {
    cpuflg_t cpuflg;

    if ((intsrcdsc == NULL) || (intisrdsc == NULL))
        {
        return FALSE;
        }

    spinlock_saveflg_cli (&intsrcdsc->lock, &cpuflg);
    list_add (&intisrdsc->list, &intsrcdsc->isrlist);
    intsrcdsc->isrnbr++;
    spinunlock_restflg_sti (&intsrcdsc->lock, &cpuflg);

    return TRUE;
    }

/*********************************************************************************
 * 
 * intrpt_return_irqnbr - 获得中断源
 * 
 * DESCRIPTION
 */

uint_t intrpt_return_irqnbr (void)
    {
    uint_t irqnbr;

    /* 读取 Interrupt request source offset 寄存器 */

    irqnbr = (uint_t) hal_io32_read (S3C2440_REG_INTOFFSET);

    return irqnbr;
    }

/*********************************************************************************
 * 
 * intrpt_clear_irqsrcpnd - 在中断管理结构体中清除中断源挂起寄存器
 * 
 * DESCRIPTION
 */

uint_t intrpt_clear_irqsrcpnd
    (
    uint_t ifdidx
    )
    {
    u32_t         clearbit;
    uint_t        flag;
    uint_t        pndbitidx;
    intsrcdsc_t * intsrcdsc;
    
    /* 获取 中断编号为 irqnbr 的 中断源描述符 */

    intsrcdsc = intrpt_return_intsrcdsc (ifdidx);

    if (intsrcdsc == NULL)
        {
        return ERROR;   /* 获取失败 */
        }

    flag      = intsrcdsc->flag & 0xFF;    /* 获取中断类型 */
    pndbitidx = intsrcdsc->pndbitidx;      /* 获取中断源在挂起寄存器中的位序 */

    if (flag == MAJINT_FLAG)
        {

        /* 主中断类型：写1 清除 Interrupt request status */

        clearbit = (1 << pndbitidx);
        hal_io32_write (S3C2440_REG_SRCPND, clearbit); 
        return OK;
        }

    if (flag == SUBINT_FLAG)
        {

        /* 子中断类型：写1 清除 Interrupt request status */

        clearbit = (1 << pndbitidx);
        hal_io32_write (S3C2440_REG_SUBSRCPND, clearbit); 
        return OK;
        }

    if (flag == EXTINT_FLAG)
        {

        /* 外部中断类型：写1 清除 Interrupt request status */

        clearbit = (1 << pndbitidx);
        hal_io32_write (S3C2440_REG_EINTPEND, clearbit); 
        return OK;
        }         

    return ERROR;
    }

/*********************************************************************************
 * 
 * intrpt_enable_irq - 打开中断源
 * 
 * DESCRIPTION
 */

uint_t intrpt_enable_irq
    (
    uint_t ifdidx
    )
    {
    u32_t         mskbit;    
    uint_t        flag;
    uint_t        pndbitidx;
    intsrcdsc_t * intsrcdsc;
   
    /* 获取 中断编号为 irqnbr 的 中断源描述符 */
    intsrcdsc = intrpt_return_intsrcdsc (ifdidx);

    if (intsrcdsc == NULL)
        {
        return ERROR;   /* 获取失败 */
        }

    flag      = intsrcdsc->flag & 0xFF;    /* 获取中断类型 */
    pndbitidx = intsrcdsc->pndbitidx;      /* 获取中断源在挂起寄存器中的位序 */

    if (flag == MAJINT_FLAG)
        {

        /* 主中断类型：读出源寄存器值, 位与屏蔽 pndbitidx 位的中断 */

        mskbit =  hal_io32_read (S3C2440_REG_INTMSK);
        mskbit &= (~(1 << pndbitidx));
        hal_io32_write (S3C2440_REG_INTMSK, mskbit); 
        return OK;
        }

    if (flag == SUBINT_FLAG)
        {

        /* 子中断类型：读出源寄存器值, 位与屏蔽 pndbitidx 位的中断 */

        mskbit =  hal_io32_read (S3C2440_REG_INTSUBMSK);
        mskbit &= (~(1 << pndbitidx));
        hal_io32_write (S3C2440_REG_INTSUBMSK, mskbit); 
        return OK;
        }

    if (flag == EXTINT_FLAG)
        {

        /* 外部中断类型：读出源寄存器值, 位与屏蔽 pndbitidx 位的中断 */

        mskbit =  hal_io32_read (S3C2440_REG_EINTMASK);
        mskbit &= (~(1 << pndbitidx));
        hal_io32_write (S3C2440_REG_EINTMASK, mskbit); 
        return OK;
        }           

    return ERROR;
    }

/*********************************************************************************
 * 
 * intrpt_disable_irq - 关闭中断源
 * 
 * DESCRIPTION
 */

uint_t intrpt_disable_irq
    (
    uint_t ifdidx
    )
    {
    u32_t         umskbit;    
    uint_t        flag;
    uint_t        pndbitidx;
    intsrcdsc_t * intsrcdsc;
   
    /* 获取 中断编号为 irqnbr 的 中断源描述符 */
    intsrcdsc = intrpt_return_intsrcdsc (ifdidx);

    if (intsrcdsc == NULL)
        {
        return ERROR;   /* 获取失败 */
        }

    flag      = intsrcdsc->flag & 0xFF;    /* 获取中断类型 */
    pndbitidx = intsrcdsc->pndbitidx;      /* 获取中断源在挂起寄存器中的位序 */

    if (flag == MAJINT_FLAG)
        {

        /* 主中断类型：读出源寄存器值, 位或使能 pndbitidx 位的中断 */

        umskbit =  hal_io32_read (S3C2440_REG_INTMSK);
        umskbit |= (1 << pndbitidx);
        hal_io32_write (S3C2440_REG_INTMSK, umskbit); 
        return OK;
        }

    if (flag == SUBINT_FLAG)
        {

        /* 子中断类型：读出源寄存器值, 位或使能 pndbitidx 位的中断 */

        umskbit =  hal_io32_read (S3C2440_REG_INTMSK);
        umskbit |= (1 << pndbitidx);
        hal_io32_write (S3C2440_REG_INTMSK, umskbit); 
        return OK;        
        }

    if (flag == EXTINT_FLAG)
        {

        /* 外部中断类型：读出源寄存器值, 位或使能 pndbitidx 位的中断 */

        umskbit =  hal_io32_read (S3C2440_REG_EINTMASK);
        umskbit |= (1 << pndbitidx);
        hal_io32_write (S3C2440_REG_EINTMASK, umskbit); 
        return OK;        
        }           

    return ERROR;    
    }
